//////////////////////////////////////
// Fast Container Library           //
// MIT License - Copyright (c) 2012 //
//////////////////////////////////////

#pragma once

#include "common.h"
#include "char_traits.h"
#include "string_utils.h"

FC_NAMESPACE_BEGIN


template <class T, size_t N>
class static_basic_string
{
public:
	typedef T							value_type;
	typedef T&							reference;
	typedef const T&					const_reference;
	typedef T*							iterator;
	typedef const T*					const_iterator;
	typedef static_basic_string<T, N>	this_type;
	typedef char_traits<T>				traits_type;

	static_basic_string()
		{
			clear();
		}

	static_basic_string( const T* s )
		{
			assign( s, s + traits_type::length(s) );
		}

	static_basic_string( const this_type& str )
		{
			assign( str.begin(), str.end() );
		}

	template <size_t U>
	static_basic_string( const static_basic_string<T, U>& str )
		{
			assign( str.begin(), str.end() );
		}

	// experimental
	template <class StrType>
	static_basic_string( const StrType& str )
		{
			assign( str.begin(), str.end() );
		}

	template <size_t U>
	this_type& operator =( const static_basic_string<T, U>& str )
	{
		assign( str.begin(), str.end() );
		return *this;
	}

	// experimental
	template <class StrType>
	this_type& operator =( const StrType& str )
	{
		assign( str.begin(), str.end() );
		return *this;
	}

	this_type& operator =( const this_type& str )	{ return assign( str.begin(), str.end() ); }
	this_type& operator =( const T* s )				{ return assign( s, s + traits_type::length(s) ); }

	this_type& assign( const T* s ) { assign( s, s + traits_type::length(s) ); }
	this_type& assign( const_iterator first, const_iterator last )
	{
		FC_ASSERT(first <= last);
		clear();
		size_t n = size_t(last - first);
		n = (n < (N - 1)) ? n : (N - 1);
		if( n > 0 )
		{
			traits_type::copy(m_data, first, n);
		}

		return *this;
	}

	bool empty() const		{ return size() == 0; }
	size_t length() const	{ return size(); }
	size_t capacity() const	{ return N - 1; }
	size_t max_size() const	{ return N - 1; }

	size_t size() const
	{
		return traits_type::length(m_data);
	}

	iterator begin()				{ return m_data; }
	const_iterator begin() const	{ return m_data; }
	iterator end()					{ return m_data + size(); }
	const_iterator end() const		{ return m_data + size(); }
	T* data()						{ return m_data; }
	const T* data() const			{ return m_data; }
	const T* c_str() const			{ return m_data; }

	reference		operator [] ( size_t i )		{ return m_data[i]; }
	const_reference operator [] ( size_t i ) const	{ return m_data[i]; }

	void clear()
	{
		traits_type::assign(m_data, N, 0);
	}

	int to_int() const { return fc::to_int(m_data); }
	float to_float() const { return fc::to_float(m_data); }

	static int compare( const T* first1, const T* last1, const T* first2, const T* last2 )
	{
		FC_ASSERT(first1 <= last1 && first2 <= last2);
		size_t d1 = size_t(last1 - first1);
		size_t d2 = size_t(last2 - first2);
		size_t n = d1 < d2 ? d1 : d2;

		int ret = traits_type::compare( first1, first2, n );
		if( ret == 0 && d1 != d2 )
			ret = (d1 < d2 ? -1 : 1);

		return ret;
	}

protected:
	T m_data[N];
	size_t m_size;

};



template <size_t N>
class static_string : public static_basic_string<char, N>
{
public:
	typedef static_basic_string<char, N>	base_type;
	typedef static_string<N>				this_type;

	static_string() : base_type() {}
	static_string( const char* s ) : base_type(s) {}
	static_string( const this_type& str ) : base_type(str) {}

	template <size_t U>
	static_string( const static_string<U>& str ) : base_type(str) {}

	template <class StrType>
	static_string( const StrType& str ) : base_type(str) {}
};





template <class T, size_t N, size_t U> inline
	bool operator ==( const static_basic_string<T, N>& a, const static_basic_string<T, U>& b )
	{
		const size_t n = N < U ? N : U;
		return (a.size() == b.size() && char_traits<T>::compare( a.c_str(), b.c_str(), n ) == 0);
	}

template <class T, size_t N, size_t U> inline
	bool operator !=( const static_basic_string<T, N>& a, const static_basic_string<T, U>& b )
	{
		return !(a == b);
	}

template <class T, size_t N> inline
	bool operator ==( const static_basic_string<T, N>& a, const T* s )
	{
		const size_t n = char_traits<T>::length(s);
		return (a.size() == n && char_traits<T>::compare( a.c_str(), s, n ) == 0);
	}

template <class T, size_t N> inline
	bool operator !=( const static_basic_string<T, N>& a, const T* s )
	{
		return !(a == s);
	}

template <class T, size_t N> inline
	bool operator ==( const T* s, const static_basic_string<T, N>& b )
	{
		return (b == s);
	}

template <class T, size_t N> inline
	bool operator !=( const T* s, const static_basic_string<T, N>& b )
	{
		return !(b == s);
	}

template <class T, size_t N, size_t U> inline
	bool operator <( const static_basic_string<T, N>& a, const static_basic_string<T, U>& b )
	{
		return static_basic_string<T, N>::compare( a.begin(), a.end(), b.begin(), b.end() ) < 0;
	}

template <class T, size_t N> inline
	bool operator <( const static_basic_string<T, N>& a, const T* s )
	{
		const size_t n = char_traits<T>::length(s);
		return static_basic_string<T, N>::compare( a.begin(), a.end(), s, s + n ) < 0;
	}

template <class T, size_t N> inline
	bool operator <( const T* s, const static_basic_string<T, N>& b )
	{
		const size_t n = char_traits<T>::length(s);
		return static_basic_string<T, N>::compare( s, s + n, b.begin(), b.end() ) < 0;
	}




FC_NAMESPACE_END


